package com.cloud.job.snail;

import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.cloud.api.domain.job.Addr;
import com.cloud.api.domain.job.ArealDistribution;
import com.cloud.api.domain.job.EvStatistics;
import com.cloud.api.domain.job.VehicleMessageDaily;
import com.cloud.core.exception.MyException;
import com.cloud.job.config.BaiduConfig;
import com.cloud.job.config.RateLimiterConfig;
import com.cloud.job.doris.DorisStreamLoad;
import com.cloud.job.service.IArealDistributionService;
import com.cloud.job.service.IVehicleDataService;
import com.cloud.job.service.IVehicleMessageDailyService;
import com.google.common.util.concurrent.RateLimiter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.util.List;

/**
 * @author 杨斌
 * 2024-03-1/3/2024
 */
@Service
@Slf4j
public class RequestBaidu {
    @Resource
    private IVehicleMessageDailyService vehicleMessageDailyService;
    @Resource
    private IArealDistributionService arealDistributionService;
    private final RestTemplate restTemplate;

    private final BaiduConfig config;

    private final RateLimiter rateLimiter;

    @Resource
    private DorisStreamLoad dorisStreamLoad;

    @Resource
    private IVehicleDataService vehicleDataService;

    @Autowired
    public RequestBaidu(RestTemplate restTemplate, BaiduConfig  config,  RateLimiterConfig rateLimiterConfig) {
        this.restTemplate = restTemplate;
        this.config = config;
        this.rateLimiter = RateLimiter.create(rateLimiterConfig.getRequestsPerSecond());
    }
    @JobExecutor(name = "vehicle_statistics")
    public void getVehicleStatistics() {
        List<EvStatistics> vehicleStatistics = vehicleDataService.getVehicleStatistics();
        vehicleStatistics.forEach(vehicleStatisticsData -> {
            String lat = String.valueOf(vehicleStatisticsData.getLat() / 1000000.0);
            String lng = String.valueOf(vehicleStatisticsData.getLng() / 1000000.0);
            try {
                rateLimiter.acquire();
                Addr addr = getAddr(lat, lng);
                if (addr != null) {
                    vehicleStatisticsData.setAddress(addr.getAddress());
                    vehicleStatisticsData.setCity(addr.getCity());
                    vehicleStatisticsData.setProvince(addr.getProvince());
                }
            } catch (Exception e) {
                // 记录异常日志，引用lat和lng
                log.error("Failed to get address for lat: {}, lng: {}", lat, lng, e);
            }
        });

        String jsonString = JSON.toJSONString(vehicleStatistics);
        try {
            dorisStreamLoad.loadJson(jsonString, EvStatistics.class);
        } catch (Exception e) {
            throw new MyException("导入数据库错误");
        }
    }


    @JobExecutor(name = "resolve_address")
    public void eval() {
        List<VehicleMessageDaily> messageDailies = vehicleMessageDailyService.getVehicleMessage();

        List<ArealDistribution> arealDistributions = messageDailies.stream().map(vehicleMessageDaily -> {
            String lat = String.valueOf(vehicleMessageDaily.getLat() / 1000000.0);
            String lng = String.valueOf(vehicleMessageDaily.getLng() / 1000000.0);

            rateLimiter.acquire();
            Addr addr = getAddr(lat, lng);
            ArealDistribution arealDistribution = new ArealDistribution();

            if (addr != null) {
                String address = addr.getAddress();
                String city = addr.getCity();
                String province = addr.getProvince();
                arealDistribution.setAddress(address);
                arealDistribution.setCity(city);
                arealDistribution.setProvince(province);
            }

            arealDistribution.setVin(vehicleMessageDaily.getVin());
            arealDistribution.setOpTime(vehicleMessageDaily.getOpTime());
            arealDistribution.setVehicleType(vehicleMessageDaily.getVehicleType());
            return arealDistribution;

        }).toList();
        String jsonString = JSON.toJSONString(arealDistributions);
        try {
            dorisStreamLoad.loadJson(jsonString, ArealDistribution.class);
        } catch (Exception e) {
            throw new MyException("车辆地址解析错误");
        }
    }
    public Addr evaluate(String lat, String lng) {
        // 在处理请求前获取许可
        rateLimiter.acquire();
        // 执行你的业务逻辑
        return getAddr(lat,lng);
    }


    public Addr getAddr(String lat, String lng) {

        String url = UriComponentsBuilder.fromHttpUrl("https://api.map.baidu.com/reverse_geocoding/v3/")
                .queryParam("ak", config.getAk())
                .queryParam("ret_coordtype", config.getRetCoordType())
                .queryParam("coordtype", config.getCoordType())
                .queryParam("extensions_poi", config.getExtensionsPoi())
                .queryParam("extensions_road", config.getExtensionsRoad())
                .queryParam("extensions_town", config.getExtensionsTown())
                .queryParam("output", "json")
                .queryParam("location", lat + "," + lng)
                .toUriString();

        String response = restTemplate.getForObject(url, String.class);
        JSONObject jsonObject = JSON.parseObject(response);
        Integer status = jsonObject.getInteger("status");
        Addr addr = null;
        if (status == 0) {
            JSONObject result = jsonObject.getJSONObject("result");
            JSONObject addressComponent = result.getJSONObject("addressComponent");
            String province = addressComponent.getString("province");
            String city = addressComponent.getString("city");
            String district = addressComponent.getString("district");
            String formattedAddressPoi = result.getString("formatted_address_poi");
            addr = new Addr(formattedAddressPoi, province, city,district);
            return addr;
        } else {
            log.error("地址解析异常: " + status);
        }
        return addr;
    }
}
